package com.mikeorth.controls
{
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextLineMetrics;
	
	import mx.collections.ArrayCollection;
	import mx.controls.ComboBox;
	import mx.controls.DataGrid;
	import mx.controls.Label;
	import mx.controls.LinkBar;
	import mx.controls.LinkButton;
	import mx.events.CollectionEvent;
	import mx.events.CollectionEventKind;
	import mx.events.ItemClickEvent;
	import mx.events.ListEvent;
	
	public class PagedDataGrid extends DataGrid
	{
		private static const PADDING_BOTTOM:Number = 30;
		private static const DEFAULT_LINK_BUTTON_PADDING:Number = 2;// top,bottom,left,right
		
		// index
		private var _index:int;
		
		public function get index ():int {
			return _index;
		}
		
		public function set index (value:int):void {
			_index = value;
			// set the style of the selected button
			linkBarChanged = true; // trigger it to set selection
			//setLinkBarSelection(_index);
			
			// enable/disable buttons
			pageCount = getPageCount();
			
			// disable paging if we are now on the last page
			if (index == pageCount-1 || pageCount == 0) {
				nextButton.enabled = false;
				lastButton.enabled = false;
			}
			else {
				nextButton.enabled = true;
				lastButton.enabled = true;
			}	
			// disable paging if we are now on the first page
			if (index == 0 || pageCount == 0) {
				prevButton.enabled = false;
				firstButton.enabled = false;
			}
			else {
				prevButton.enabled = true;
				firstButton.enabled = true;
			}
			setChunk(index);
		}


		private var pageCount:int;
		private var linkBarChanged:Boolean = false;
		
		// masterList
		/**
		 * Use this as primary dataProvider in parent component.
		 */		
		
		private var _masterList:ArrayCollection;
		[Bindable(event="masterListChange")]
		public function set masterList (value:ArrayCollection):void
		{
			if (value != _masterList)
			{
				if (_masterList)
				{
					_masterList.removeEventListener
						(CollectionEvent.COLLECTION_CHANGE, onMasterListChange);
				}
				_masterList = value;
				refreshData();
				
				if (_masterList)
				{
					_masterList.addEventListener
						(CollectionEvent.COLLECTION_CHANGE, onMasterListChange);
				}
				dispatchEvent (new Event ("masterListChange"));
			}
		}

		public function get masterList ():ArrayCollection
		{
			return _masterList;
		}

		private function onMasterListChange (event:CollectionEvent):void
		{
			if ((event.kind == CollectionEventKind.ADD) ||
				(event.kind == CollectionEventKind.REMOVE) ||
				(event.kind == CollectionEventKind.REPLACE) ||
				(event.kind == CollectionEventKind.RESET))
			{
				dispatchEvent (new Event ("masterListChange"));
			}
			refreshData();
		}


		// chunk
		private var _chunk:Array = [];

		public function get chunk ():Array {
			return _chunk;
		}
		
		public function set chunk (value:Array):void {
			_chunk = value;
			this.dataProvider = _chunk;
		}

		// itemCount
		private var _itemCount:int = 20;
		public function get itemCount ():int {
			return _itemCount;
		}
		
		public function set itemCount (value:int):void {
			_itemCount = value;
			// reset nav bar
			if (_masterList) // null ref check for error on init
				refreshData();
		}

		public var linkBar:LinkBar;
		
		public var nextButton:LinkButton;
		public var prevButton:LinkButton;
		public var lastButton:LinkButton;
		public var firstButton:LinkButton;
		private var itemCombo:ComboBox;
		private var totalCountLabel:Label;
		private var numberItemsLabel:Label;
						
		public function PagedDataGrid()
		{
		}
		
		/*  LISTENERS */

		private function first(event:MouseEvent):void {
			index = 0;
		}
		private function last(event:MouseEvent):void {
			index = pageCount - 1;
		}	
				
		private function next(event:MouseEvent):void {
			index++;
		}
		private function prev(event:MouseEvent):void {
			index--;
		}
		
		private function onComboChange(event:ListEvent):void {
			var str:String = event.currentTarget.selectedItem.toString();
			if (str.substr(0,3) == 'All') {
				itemCount = _masterList.length;
			}
			else {
				itemCount = Number(event.currentTarget.selectedItem);
			}
		}
		
		private var lastSelectedPageIndex:int = -1;
		private function onLinkBarClick(event:ItemClickEvent):void {
			index = event.index;
		}
		
		/*----------------- HELPER FUNCS -----------------*/
		
		/**
		 * Sets the currently selected page style and deselects the previous one. 
		 * @param index
		 * 
		 */		
		private function setLinkBarSelection(index:int):void {
			// make sure linkbar has been created first
			if (linkBar.dataProvider && linkBar.dataProvider.length > 0) {
				var _btn:LinkButton = linkBar.getChildAt(index) as LinkButton;
				_btn.setStyle('textDecoration', 'underline');
				
				// clear out the previously selected style. 
				// make sure it's not the same page.
				// make sure it is within bounds
				if (lastSelectedPageIndex >= 0 && index != lastSelectedPageIndex && lastSelectedPageIndex < linkBar.numChildren) {
					var _prevBtn:LinkButton = linkBar.getChildAt(lastSelectedPageIndex) as LinkButton;
					_prevBtn.setStyle('textDecoration', 'normal');
				}
				lastSelectedPageIndex = index;
			}
		}
		
		private function getPageCount():int {
			// if "All" is selected or the masterList is null, then always return 1
			if (itemCombo.selectedItem == "All" || !_masterList) {
				_itemCount = _masterList.length;				
				return 1;
			}
			return Math.ceil(_masterList.length / _itemCount);
		}
			
		private function refreshData():void {
			// reset to first page
			index = 0;
			// find the number of pages
			pageCount = getPageCount();
			// setup linkbar
			setupNavigation(pageCount);
			setChunk(index);
		}
		/**
		 * Dynamically creates dataProvider for linkbar to show page numbers.
		 * If pageCount == 0 or 1, then pages will not be shown 
		 * @param pageCount
		 */		
		private function setupNavigation(pageCount:int):void {
			var _dp:Array = [];
			if (pageCount > 1) {
				for (var i:uint=0; i < pageCount; i++) {
					_dp.push(i+1);
				}
			}

			linkBar.dataProvider = _dp;
			linkBar.toolTip = "Select page";
			linkBarChanged = true;
			invalidateDisplayList();
		}
		
		/**
		 * Sets the current page chunk from the masterList based on the index. 
		 * @param index
		 * 
		 */		
		private function setChunk(index:int):void {
			// slice array at new starting index
			var startIndex:int = index * _itemCount;
			var endIndex:int = startIndex + _itemCount;
			chunk = masterList.toArray().slice(startIndex, endIndex);
		}
		
		
		/* PROPERTY OVERRIDES */
		
		override public function set dataProvider(value:Object):void {
			
			//masterList = value as ArrayCollection;
			//setChunk(index);

			super.dataProvider = _chunk;
		}
		
		
		/* FRAMEWORK OVERRIDES */
		
		override protected function createChildren():void {
			super.createChildren();

			if (!firstButton) {
				firstButton = new LinkButton();
				firstButton.label = "<<";
				firstButton.toolTip = "First";
				firstButton.setActualSize(30,20);
				firstButton.addEventListener(MouseEvent.CLICK, first);
				firstButton.setStyle("paddingLeft",DEFAULT_LINK_BUTTON_PADDING);
				firstButton.setStyle("paddingRight",DEFAULT_LINK_BUTTON_PADDING);
				addChild(firstButton);
			}			
			if (!lastButton) {
				lastButton = new LinkButton();
				lastButton.label = ">>";
				lastButton.toolTip = "Last";
				lastButton.setActualSize(40,20);
				lastButton.addEventListener(MouseEvent.CLICK, last);
				firstButton.setStyle("paddingLeft", DEFAULT_LINK_BUTTON_PADDING);
				firstButton.setStyle("paddingRight",DEFAULT_LINK_BUTTON_PADDING);
				addChild(lastButton);
			}		
			if (!nextButton) {
				nextButton = new LinkButton();
				nextButton.label = ">";
				nextButton.toolTip = "Next";
				nextButton.setActualSize(25,20);
				nextButton.addEventListener(MouseEvent.CLICK, next);
				firstButton.setStyle("paddingLeft",DEFAULT_LINK_BUTTON_PADDING);
				firstButton.setStyle("paddingRight",DEFAULT_LINK_BUTTON_PADDING);
				addChild(nextButton);
			}
			if (!prevButton) {
				prevButton = new LinkButton();
				prevButton.label = "<";
				prevButton.toolTip = "Previous";
				prevButton.setActualSize(25,20);
				prevButton.addEventListener(MouseEvent.CLICK, prev);
				firstButton.setStyle("paddingLeft",DEFAULT_LINK_BUTTON_PADDING);
				firstButton.setStyle("paddingRight",DEFAULT_LINK_BUTTON_PADDING);
				addChild(prevButton);				
			}
		
			if (!linkBar) {
				linkBar = new LinkBar();
				firstButton.setStyle("paddingLeft",DEFAULT_LINK_BUTTON_PADDING);
				firstButton.setStyle("paddingRight",DEFAULT_LINK_BUTTON_PADDING);
				linkBar.addEventListener(ItemClickEvent.ITEM_CLICK, onLinkBarClick);
				addChild(linkBar);
			}
			
			if (!itemCombo) {
				itemCombo = new ComboBox();
				var _dp:Array = [];
				_dp.push(2);
				_dp.push(5);
				_dp.push(10);
				_dp.push("All");
				itemCombo.dataProvider = _dp;
				itemCombo.setActualSize(60, 20);
				itemCombo.addEventListener(ListEvent.CHANGE, onComboChange);
				itemCombo.setStyle('styleName', 'pagingComboBox');
				itemCombo.selectedIndex = 1; // preselect "20"
				addChild(itemCombo);
			}
			if (!numberItemsLabel) {
				numberItemsLabel = new Label();
				numberItemsLabel.setStyle("fontSize", 11);
				addChild(numberItemsLabel);
			}
			if (!totalCountLabel) {
				totalCountLabel = new Label();
				
			}
		}

		override protected function commitProperties():void {
			super.commitProperties();
			// set text and get total number of entires
			if (_masterList) {
				if (_itemCount == _masterList.length) {
					numberItemsLabel.text = " " +  _masterList.length + " items"
				}
				else {
					numberItemsLabel.text = " items per page (" + _masterList.length + " total items)"
				}
								
			}

		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight-PADDING_BOTTOM);
			var _y:Number = unscaledHeight - PADDING_BOTTOM + 3;
			
			var _lineMetrics:TextLineMetrics = numberItemsLabel.getLineMetrics(0);
			var xLinkBar:int = 0;
			var xSpacer:int = 29;
						
			if (linkBarChanged) {
				linkBarChanged = false;
				// set width to number of pages * 25px
				linkBar.setActualSize(pageCount * xSpacer, 28);
				// select first page
				setLinkBarSelection(index);
			}		
			// set the items label, add padding to height & width
			numberItemsLabel.setActualSize(_lineMetrics.width+10, _lineMetrics.height + 5);		
 			if (firstButton.visible)
			{
				xLinkBar = xSpacer;
			}
			if (prevButton.visible)
			{
				xLinkBar += xSpacer;
			} 
			// position buttons at the bottom
			firstButton.move(0, _y + 3);
			prevButton.move(xSpacer, _y + 3);
			linkBar.move(xLinkBar, _y)
			// subtract 15 pixels to postion better
			nextButton.move(linkBar.x + linkBar.width - 15, _y + 3);
			lastButton.move((linkBar.x + linkBar.width - 22) + xSpacer, _y + 3);
			numberItemsLabel.move(unscaledWidth - numberItemsLabel.width, _y+6)
			itemCombo.move(unscaledWidth - itemCombo.width - numberItemsLabel.width, _y+3);
		}

	}
}